/*
 *
 *      Copyright (c) 2018-2025, cloud All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the pig4cloud.com developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: cloud
 *
 */

package com.fuyao.cloud.admin.controller;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyao.cloud.admin.api.dto.MenuSearchDTO;
import com.fuyao.cloud.admin.api.dto.SysMenuDTO;
import com.fuyao.cloud.admin.api.dto.SysRoleMenuDTO;
import com.fuyao.cloud.admin.api.dto.UserSsoDTO;
import com.fuyao.cloud.admin.api.entity.SysMenu;
import com.fuyao.cloud.admin.api.entity.SysRole;
import com.fuyao.cloud.admin.api.entity.SysUser;
import com.fuyao.cloud.admin.api.vo.MenuVo;
import com.fuyao.cloud.admin.constant.UserConstants;
import com.fuyao.cloud.admin.service.SysMenuService;
import com.fuyao.cloud.admin.service.SysUserService;
import com.fuyao.cloud.common.core.constant.CacheConstants;
import com.fuyao.cloud.common.core.constant.SecurityConstants;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.log.annotation.SysLog;
import com.fuyao.cloud.common.security.service.CloudUser;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author cloud
 * @date 2017/10/31
 */
@RestController
@AllArgsConstructor
@RequestMapping("/menu")
@Api(value = "menu", tags = "菜单管理模块")
public class SysMenuController {

	private final SysMenuService sysMenuService;

	private final SysUserService userService;

	private final RedisTemplate redisTemplate;

	/**
	 * 返回当前用户的树形菜单集合
	 * @param type 类型
	 * @param parentId 父节点ID
	 * @return 当前用户的树形菜单
	 */
	@GetMapping
	public R getUserMenu(String type, Long parentId) {
		CloudUser cloudUser = SecurityUtils.getUser();
		String username = cloudUser.getUsername();
		Long tenantId = cloudUser.getTenantId();
		SecurityUtils.getRoles().forEach(role->{
			redisTemplate.delete(tenantId+":"+CacheConstants.MENU_DETAILS+"::"+ role);
		});

		SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
		UserSsoDTO userSsoDTO =userService.getUserSsoDtoById(user.getUserId());
		redisTemplate.opsForHash().put(UserConstants.SSO_REDIS_USERS_KES,username,userSsoDTO);
		// 获取符合条件的菜单
		Set<SysMenu> all = new HashSet<>();
		SecurityUtils.getRoles().forEach(roleId -> all.addAll(sysMenuService.findMenuByRoleId(roleId)));
		return R.ok(sysMenuService.filterMenu(all, type, parentId));
	}

	/**
	 * 返回树形菜单集合
	 * @param lazy 是否是懒加载
	 * @param parentId 父节点ID
	 * @return 树形菜单
	 */
	@GetMapping(value = "/tree")
	public R getTree(Long parentId, String menuName) {
		return R.ok(sysMenuService.treeMenu(parentId, menuName));
	}

	/**
	 * 返回角色的菜单集合
	 * @param roleId 角色ID
	 * @return 属性集合
	 */
	@GetMapping("/tree/{roleId}")
	public R getRoleTree(@PathVariable Long roleId) {
		return R.ok(
				sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getMenuId).collect(Collectors.toList()));
	}

	/**
	 * 通过ID查询菜单的详细信息
	 * @param id 菜单ID
	 * @return 菜单详细信息
	 */
	@GetMapping("/{id}")
	public R getById(@PathVariable Long id) {
		return R.ok(sysMenuService.getById(id));
	}

	/**
	 * 新增菜单
	 * @param sysMenu 菜单信息
	 * @return success/false
	 */
	@SysLog("新增菜单")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('sys_menu_add')")
	public R save(@Valid @RequestBody SysMenu sysMenu) {
		sysMenuService.save(sysMenu);
		return R.ok(sysMenu);
	}

	/**
	 * 删除菜单
	 * @param id 菜单ID
	 * @return success/false
	 */
	@SysLog("删除菜单")
	@DeleteMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('sys_menu_del')")
	public R removeById(@PathVariable Long id) {
		return sysMenuService.removeMenuById(id);
	}

	/**
	 * 更新菜单
	 * @param sysMenu
	 * @return
	 */
	@SysLog("更新菜单")
	@PutMapping
	@PreAuthorize("@pms.hasPermission('sys_menu_edit')")
	public R update(@Valid @RequestBody SysMenu sysMenu) {
		return R.ok(sysMenuService.updateMenuById(sysMenu));
	}

	@SysLog("更新菜单数据权限")
	@PutMapping("/updateMenuDataScope")
	@PreAuthorize("@pms.hasPermission('sys_menu_edit')")
	public R updateMenuDataScope(@Valid @RequestBody SysMenuDTO menuDTO) {
		return R.ok(sysMenuService.updateMenuDataScope(menuDTO));
	}


	@PostMapping("/findMenuByPath/{path}")
	public R<List<MenuVo>> findMenuByPath(@PathVariable("path") String path) {
		MenuSearchDTO searchDTO = new MenuSearchDTO();
		searchDTO.setPath(path);
		return R.ok(sysMenuService.findMenuVOList(searchDTO));
	}

	@PostMapping("/findMenuByPermission/{permission}")
	public R<List<MenuVo>> findMenuByPermission(@PathVariable("permission") String permission) {
		MenuSearchDTO searchDTO = new MenuSearchDTO();
		searchDTO.setPermission(permission);
		return R.ok(sysMenuService.findMenuVOList(searchDTO));
	}

	@PostMapping("/findMenuDataScopeList")
	public R<List<MenuVo>> findMenuDataScopeList(@RequestBody SysRoleMenuDTO menuDTO) {
		return R.ok(sysMenuService.findMenuDataScopeList(menuDTO));
	}

	@PostMapping("/menuRolePage")
	public R getMenuRolePage(Page page, SysRoleMenuDTO menuDTO) {
		return R.ok(sysMenuService.getMenuRolePage(page, menuDTO));
	}


	@PostMapping("/getMenuRoleTree")
	public R<List<Tree<Long>>> getMenuRoleTree(@RequestBody SysRoleMenuDTO menuDTO) {
		List<Tree<Long>> menuRoleTreeList = sysMenuService.getMenuRoleTree(sysMenuService.findMenuDataScopeList(menuDTO));
		return R.ok(menuRoleTreeList);
	}


}
